import functools
import time
from typing import Callable, Type, Tuple, Union


def retry(
        max_retries: int = 3,
        delay: float = 1,
        exceptions: Union[Type[Exception], Tuple[Type[Exception], ...]] = Exception
):
    """
    重试装饰器，捕获异常后自动重试N次
    :param max_retries: 最大重试次数（默认3次）
    :param delay: 每次重试间隔秒数（默认1秒）
    :param exceptions: 需要捕获的异常类型（默认捕获所有异常）
    """

    def decorator(func: Callable):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            retries = 0
            last_error = None

            while retries < max_retries:
                try:
                    return func(*args, **kwargs)
                except exceptions as e:
                    last_error = e
                    retries += 1
                    if retries < max_retries:
                        print(f"Retry {retries}/{max_retries} after error: {str(e)}")
                        time.sleep(delay)

            raise Exception(
                f"Function {func.__name__} failed after {max_retries} retries. Last error: {str(last_error)}")

        return wrapper

    return decorator


# 使用示例
@retry(max_retries=3, delay=2, exceptions=(ConnectionError, TimeoutError))
def fetch_data():
    print("Attempting to fetch data...")
    raise ConnectionError("Network unreachable")


if __name__ == '__main__':
    # 调用函数（将触发3次重试）
    fetch_data()
